package com.framework.view.indicator.indicators;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.view.View;

import com.framework.view.indicator.CalculationHelper;
import com.framework.view.indicator.IPageIndicator;
import com.framework.view.indicator.indicators.configs.LineIndicatorConfig;
import com.framework.view.indicator.model.IndicatorShapeType;
import com.framework.view.indicator.model.IndicatorWidthModel;
import com.framework.view.indicator.model.PositionInfo;
import com.framework.view.indicator.util.ArgbEvaluatorHolder;

import java.util.ArrayList;
import java.util.List;

/**
 * 线性指示器
 *
 * @author liangzx
 * @version 1.0
 * @time 2019-12-17 12:43
 **/
public class LineIndicatorView extends View implements IPageIndicator<LineIndicatorConfig> {

    /**
     * 指示器配置
     */
    private LineIndicatorConfig mIndicatorConfig;
    /**
     * 绘制区域
     */
    private RectF mLineRect = new RectF();
    /**
     * 三角形绘制路径
     */
    private Path mSharpCornerPath;
    /**
     * 贝塞尔曲线绘制路径
     */
    private Path mBezierPath;
    /**
     * 标题位置信息列表
     */
    private List<PositionInfo> mPositions;
    /**
     * 画笔
     */
    private Paint mPaint;
    //贝塞尔曲线所用变量
    private float mLeftCircleRadius;
    private float mLeftCircleX;
    private float mRightCircleRadius;
    private float mRightCircleX;
    private int mMaxCircleRadius;
    private int mMinCircleRadius;

    public LineIndicatorView(Context context) {
        super(context);
    }

    @Override
    public void init(LineIndicatorConfig config, int totalCount, int position) {
        mIndicatorConfig = config;
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(config.getColor(position));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mIndicatorConfig.getShapeType() == IndicatorShapeType.ROUND_RECT) {
            canvas.drawRoundRect(mLineRect, mIndicatorConfig.getRoundRadius(), mIndicatorConfig.getRoundRadius(), mPaint);
        } else if (mIndicatorConfig.getShapeType() == IndicatorShapeType.CIRCLE) {
            if (mIndicatorConfig.isUseBezierEffect() && null != mBezierPath) {
                float y = mLineRect.top + mLineRect.height() / 2;
                canvas.drawCircle(mLeftCircleX, y, mLeftCircleRadius, mPaint);
                canvas.drawCircle(mRightCircleX, y, mRightCircleRadius, mPaint);
                canvas.drawPath(mBezierPath, mPaint);
            } else {
                canvas.drawCircle(mLineRect.left + mLineRect.width() / 2, mLineRect.top + mLineRect.height() / 2, getCircleDiameter() / 2, mPaint);
            }
        } else {
            canvas.drawRect(mLineRect, mPaint);
        }
        if (mIndicatorConfig.isShowSharpCorner() && null != mSharpCornerPath) {
            canvas.drawPath(mSharpCornerPath, mPaint);
        }
    }

    @Override
    public void updateTitlePositions(List<PositionInfo> positions) {
        boolean isInit = null == mPositions || mPositions.isEmpty();
        mPositions = positions;
        if (mIndicatorConfig.isShowSharpCorner()) {
            mSharpCornerPath = new Path();
        }
        if (mIndicatorConfig.isUseBezierEffect()) {
            mBezierPath = new Path();
        }
        if (isInit) {
            updateRect(0);
        }
    }

    /**
     * 更新绘制区域
     *
     * @param position
     */
    private void updateRect(int position) {
        mPaint.setColor(mIndicatorConfig.getColor(position));
        if (null == mPositions || mPositions.isEmpty()) {
            return;
        }
        final PositionInfo positionInfo;
        if (position >= mPositions.size()) {
            positionInfo = mPositions.get(mPositions.size() - 1);
        } else if (position < 0) {
            positionInfo = mPositions.get(0);
        } else {
            positionInfo = mPositions.get(position);
        }
        //线上下坐标
        if (mIndicatorConfig.isTop()) {
            mLineRect.top = positionInfo.top + mIndicatorConfig.getPendingTop();
            mLineRect.bottom = mLineRect.top + mIndicatorConfig.getHeight();
        } else {
            mLineRect.bottom = positionInfo.bottom - mIndicatorConfig.getPendingBottom();
            mLineRect.top = mLineRect.bottom - mIndicatorConfig.getHeight();
        }
        //有小尖角的情况，线为全屏
        if (mIndicatorConfig.isShowSharpCorner()) {
            mSharpCornerPath.reset();
            final int halfWid = mIndicatorConfig.getSharpCornerWidth() / 2;
            final float firstX = positionInfo.horizontalCenter() - halfWid;
            final float firstY = mIndicatorConfig.isTop() ? mLineRect.bottom : mLineRect.top;
            final float secondY = (mIndicatorConfig.isTop() ? firstY + mIndicatorConfig.getSharpCornerHeight() : firstY - mIndicatorConfig.getSharpCornerHeight());
            mSharpCornerPath.moveTo(firstX, firstY);
            mSharpCornerPath.lineTo(firstX + halfWid, secondY);
            mSharpCornerPath.lineTo(firstX + mIndicatorConfig.getSharpCornerWidth(), firstY);
            mSharpCornerPath.close();
            mLineRect.left = 0;
            mLineRect.right = getWidth();
        } else {
            if (mIndicatorConfig.getWidthModel() == IndicatorWidthModel.MATCH_EDGE) {
                mLineRect.left = positionInfo.left + mIndicatorConfig.getPendingLeft();
                mLineRect.right = positionInfo.right - mIndicatorConfig.getPendingRight();
            } else if (mIndicatorConfig.getWidthModel() == IndicatorWidthModel.WARP_CONTENT) {
                mLineRect.left = positionInfo.contentLeft + mIndicatorConfig.getPendingLeft();
                mLineRect.right = positionInfo.contentRight - mIndicatorConfig.getPendingRight();
            } else {
                mLineRect.left = positionInfo.left + ((positionInfo.getWidth() - mIndicatorConfig.getWidth()) >> 1);
                mLineRect.right = mLineRect.left + mIndicatorConfig.getWidth();
            }
        }
    }

    /**
     * 返回圆的直径
     *
     * @return
     */
    private int getCircleDiameter() {
        int diameter;
        if (mIndicatorConfig.getWidth() == 0) {
            diameter = mIndicatorConfig.getHeight();
        } else if (mIndicatorConfig.getHeight() == 0) {
            diameter = mIndicatorConfig.getWidth();
        } else {
            diameter = Math.max(mIndicatorConfig.getHeight(), mIndicatorConfig.getWidth());
        }
        return diameter;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (null == mPositions || mPositions.isEmpty()) {
            return;
        }
        // 计算颜色
        if (mIndicatorConfig.isMultiColors()) {
            int color;
            if (mIndicatorConfig.isColorFollowSlideChange()) {
                final ArrayList<Integer> colors = mIndicatorConfig.getColors();
                int currentColor = colors.get(Math.abs(position) % colors.size());
                int nextColor = colors.get(Math.abs(position + 1) % colors.size());
                color = ArgbEvaluatorHolder.eval(positionOffset, currentColor, nextColor);
            } else {
                color = mIndicatorConfig.getColor(position);
            }
            mPaint.setColor(color);
        }

        // 计算锚点位置
        PositionInfo current = CalculationHelper.getImitativePosition(mPositions, position);
        PositionInfo next = CalculationHelper.getImitativePosition(mPositions, position + 1);

        if (mIndicatorConfig.isTop()) {
            mLineRect.top = current.top + mIndicatorConfig.getPendingTop();
            mLineRect.bottom = mLineRect.top + mIndicatorConfig.getHeight();
        } else {
            mLineRect.bottom = current.bottom - mIndicatorConfig.getPendingBottom();
            mLineRect.top = mLineRect.bottom - mIndicatorConfig.getHeight();
        }

        float leftX;
        float nextLeftX;
        float rightX;
        float nextRightX;
        if (mIndicatorConfig.isShowSharpCorner()) {
            final int halfWid = mIndicatorConfig.getSharpCornerWidth() / 2;
            leftX = current.left + (current.getWidth() >> 1) - halfWid;
            nextLeftX = next.left + (next.getWidth() >> 1) - halfWid;
            mSharpCornerPath.reset();
            final float firstX = leftX + (nextLeftX - leftX) * mIndicatorConfig.getStartInterpolator().getInterpolation(positionOffset);
            final float firstY = mIndicatorConfig.isTop() ? mLineRect.bottom : mLineRect.top;
            final float secondY = (mIndicatorConfig.isTop() ? firstY + mIndicatorConfig.getSharpCornerHeight() : firstY - mIndicatorConfig.getSharpCornerHeight());
            mSharpCornerPath.moveTo(firstX, firstY);
            mSharpCornerPath.lineTo(firstX + halfWid, secondY);
            mSharpCornerPath.lineTo(firstX + mIndicatorConfig.getSharpCornerWidth(), firstY);
            mSharpCornerPath.close();
            mLineRect.left = 0;
            mLineRect.right = getWidth();
        } else if (mIndicatorConfig.isUseBezierEffect()) {
            mBezierPath.reset();
            mMaxCircleRadius = getCircleDiameter() / 2;
            mMinCircleRadius = (int) (mMaxCircleRadius * 0.8);
            leftX = current.left + ((current.right - current.left) >> 1);
            rightX = next.left + ((next.right - next.left) >> 1);
            mLeftCircleX = leftX + (rightX - leftX) * mIndicatorConfig.getStartInterpolator().getInterpolation(positionOffset);
            mRightCircleX = leftX + (rightX - leftX) * mIndicatorConfig.getEndInterpolator().getInterpolation(positionOffset);
            mLeftCircleRadius = mMaxCircleRadius + (mMinCircleRadius - mMaxCircleRadius) * mIndicatorConfig.getEndInterpolator().getInterpolation(positionOffset);
            mRightCircleRadius = mMinCircleRadius + (mMaxCircleRadius - mMinCircleRadius) * mIndicatorConfig.getStartInterpolator().getInterpolation(positionOffset);

            float y = mLineRect.top + mLineRect.height() / 2;
            mBezierPath.moveTo(mRightCircleX, y);
            mBezierPath.lineTo(mRightCircleX, y - mRightCircleRadius);
            mBezierPath.quadTo(mRightCircleX + (mLeftCircleX - mRightCircleX) / 2.0f, y, mLeftCircleX, y - mLeftCircleRadius);
            mBezierPath.lineTo(mLeftCircleX, y + mLeftCircleRadius);
            mBezierPath.quadTo(mRightCircleX + (mLeftCircleX - mRightCircleX) / 2.0f, y, mRightCircleX, y + mRightCircleRadius);
            mBezierPath.close();
        } else {
            if (mIndicatorConfig.getWidthModel() == IndicatorWidthModel.MATCH_EDGE) {
                leftX = current.left + mIndicatorConfig.getPendingLeft();
                nextLeftX = next.left + mIndicatorConfig.getPendingLeft();
                rightX = current.right - mIndicatorConfig.getPendingRight();
                nextRightX = next.right - mIndicatorConfig.getPendingRight();
            } else if (mIndicatorConfig.getWidthModel() == IndicatorWidthModel.WARP_CONTENT) {
                leftX = current.contentLeft + mIndicatorConfig.getPendingLeft();
                nextLeftX = next.contentLeft + mIndicatorConfig.getPendingLeft();
                rightX = current.contentRight - mIndicatorConfig.getPendingRight();
                nextRightX = next.contentRight - mIndicatorConfig.getPendingRight();
            } else {
                leftX = current.left + ((current.getWidth() - mIndicatorConfig.getWidth()) >> 1);
                nextLeftX = next.left + ((next.getWidth() - mIndicatorConfig.getWidth()) >> 1);
                rightX = current.left + ((current.getWidth() + mIndicatorConfig.getWidth()) >> 1);
                nextRightX = next.left + ((next.getWidth() + mIndicatorConfig.getWidth()) >> 1);
            }
            mLineRect.left = leftX + (nextLeftX - leftX) * mIndicatorConfig.getStartInterpolator().getInterpolation(positionOffset);
            mLineRect.right = rightX + (nextRightX - rightX) * mIndicatorConfig.getEndInterpolator().getInterpolation(positionOffset);
        }
        invalidate();
    }

    @Override
    public void onPageSelected(int position) {
        updateRect(position);
        invalidate();
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }

    @Override
    public void onEntering(int index, int totalCount, float enterPercent, boolean leftToRight) {
    }

    @Override
    public void onLeaving(int index, int totalCount, float leavePercent, boolean leftToRight) {
    }

    @Override
    public void onSelected(int index, int totalCount) {
    }

    @Override
    public void onCancelSelected(int index, int totalCount) {
    }

//    @Override
//    protected void onDetachedFromWindow() {
//        super.onDetachedFromWindow();
//        if (null != mPositions) {
//            mPositions.clear();
//        }
//    }
}
